package service

import (
	uuid "github.com/satori/go.uuid"
	"gorm.io/gorm"
	"shop-bean/constant"
	"shop-bean/dto"
	"shop-bean/model"
	"shop-bean/request"
	"shop-common/library/loggerV2"
	"shop-common/library/variables"
	"shop-common/utils/pagehelper"
	"shop-common/utils/queryWrapper"
	"shop-service/repository"
)

type IShippingTemplatesService interface {
	Create(request *request.ShippingTemplatesRequest) error
	Update(request *request.ShippingTemplatesRequest) error
	FindSimple() ([]*model.ShippingTemplates, error)
	FindPage(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error)
	FindById(id uint) (*dto.ShippingTemplatesDTO, error)
	BatchDelete(ids []uint) error
}

type ShippingTemplatesService struct {
	db                *gorm.DB
	regionService     IShippingTemplatesRegionService
	freeService       IShippingTemplatesFreeService
	noDeliveryService IShippingTemplatesNoDeliveryService
	repository        repository.IShippingTemplatesRepository
}

func NewShippingTemplatesService() IShippingTemplatesService {
	return &ShippingTemplatesService{
		db:                variables.GormDB(),
		regionService:     NewShippingTemplatesRegionService(),
		freeService:       NewShippingTemplatesFreeService(),
		noDeliveryService: NewShippingTemplatesNoDeliveryService(),
		repository:        repository.NewShippingTemplatesRepository(),
	}
}

func (s *ShippingTemplatesService) Create(request *request.ShippingTemplatesRequest) error {
	tmpl := &model.ShippingTemplates{
		Name:       request.Name,
		Type:       request.Type,
		Appoint:    request.Appoint,
		NoDelivery: request.NoDelivery,
		Seq:        request.Seq,
	}

	return s.db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&tmpl).Error; err != nil {
			loggerV2.Error(err)
			return err
		}

		if err := tx.Create(setShippingTemplatesRegionList(tmpl.Id, request.Type, request)).Error; err != nil {
			loggerV2.Error(err)
			return err
		}

		if request.Appoint == constant.GLOBAL_ENABLE && len(request.AppointList) > 0 {
			if err := tx.Create(setShippingTemplatesFree(tmpl.Id, request.Type, request)).Error; err != nil {
				loggerV2.Error(err)
				return err
			}
		}

		if request.NoDelivery == constant.GLOBAL_ENABLE && len(request.NoDeliveryList) > 0 {
			if err := tx.Create(setShippingTemplatesNoDelivery(tmpl.Id, request)).Error; err != nil {
				loggerV2.Error(err)
				return err
			}
		}

		return nil
	})
}

//地区运费集合
func setShippingTemplatesRegionList(tempId uint, _type uint8, request *request.ShippingTemplatesRequest) (regions []*model.ShippingTemplatesRegion) {
	for _, item := range request.RegionList {
		uniq := uuid.NewV4().String()
		for _, r := range item.Region {
			if len(r.Children) > 0 {
				for _, city := range r.Children {
					regions = append(regions, &model.ShippingTemplatesRegion{
						TempId:       tempId,
						ProvinceId:   r.CityId,
						CityId:       city.CityId,
						First:        item.First,
						FirstPrice:   item.FirstPrice,
						Renewal:      item.Renewal,
						RenewalPrice: item.RenewalPrice,
						Type:         _type,
						UniqId:       uniq,
						Status:       true,
					})
				}
			} else {
				regions = append(regions, &model.ShippingTemplatesRegion{
					TempId:       tempId,
					ProvinceId:   r.CityId,
					CityId:       0,
					First:        item.First,
					FirstPrice:   item.FirstPrice,
					Renewal:      item.Renewal,
					RenewalPrice: item.RenewalPrice,
					Type:         _type,
					UniqId:       uniq,
					Status:       true,
				})
			}
		}
	}

	return regions
}

//包邮集合
func setShippingTemplatesFree(tempId uint, _type uint8, request *request.ShippingTemplatesRequest) (frees []*model.ShippingTemplatesFree) {
	for _, item := range request.AppointList {
		uniq := uuid.NewV4().String()
		for _, r := range item.Place {
			for _, city := range r.Children {
				free := &model.ShippingTemplatesFree{
					ProvinceId: r.CityId,
					TempId:     tempId,
					CityId:     city.CityId,
					Number:     item.Number,
					Price:      item.Price,
					Type:       _type,
					UniqId:     uniq,
					Status:     true,
				}

				frees = append(frees, free)
			}
		}
	}

	return
}

//不送达集合
func setShippingTemplatesNoDelivery(tempId uint, request *request.ShippingTemplatesRequest) (noDeliverys []*model.ShippingTemplatesNoDelivery) {
	for _, item := range request.NoDeliveryList {
		uniq := uuid.NewV4().String()
		for _, r := range item.Place {
			for _, city := range r.Children {
				noDelivery := &model.ShippingTemplatesNoDelivery{
					ProvinceId: r.CityId,
					TempId:     tempId,
					CityId:     city.CityId,
					UniqId:     uniq,
				}
				noDeliverys = append(noDeliverys, noDelivery)
			}
		}
	}

	return
}

func (s *ShippingTemplatesService) Update(request *request.ShippingTemplatesRequest) error {
	columns := make(map[string]interface{})
	columns["name"] = request.Name
	columns["type"] = request.Type
	columns["appoint"] = request.Appoint
	columns["no_delivery"] = request.NoDelivery
	columns["seq"] = request.Seq

	return s.db.Transaction(func(tx *gorm.DB) error {
		//主表
		if err := s.repository.Updates(tx, request.Id, columns); err != nil {
			loggerV2.Error(err)
			return err
		}

		//设置区域配送
		if err := s.regionService.BatchDelete(tx, []uint{request.Id}); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesRegion failed: err %v, id %d", err, request.Id)
			return err
		}
		regions := setShippingTemplatesRegionList(request.Id, request.Type, request)
		if err := tx.Create(regions).Error; err != nil {
			loggerV2.Error(err)
			return err
		}

		//设置指定包邮
		if err := s.freeService.BatchDelete(tx, []uint{request.Id}); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesFree failed: err %v, id %d", err, request.Id)
			return err
		}
		if request.Appoint == 1 && len(request.AppointList) > 0 {
			if err := tx.Create(setShippingTemplatesFree(request.Id, request.Type, request)).Error; err != nil {
				loggerV2.Error(err)
				return err
			}
		}

		//设置不送达
		if err := s.noDeliveryService.BatchDelete(tx, []uint{request.Id}); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesNoDelivery failed: err %v, id %d", err, request.Id)
			return err
		}
		if request.NoDelivery == 1 && len(request.NoDeliveryList) > 0 {
			if err := tx.Create(setShippingTemplatesNoDelivery(request.Id, request)).Error; err != nil {
				loggerV2.Error(err)
				return err
			}
		}

		return nil
	})
}

func (s *ShippingTemplatesService) FindPage(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error) {
	paginator := pagehelper.New().SetOffset(request).SetFilter([]string{"id"}).
		IsPush(request.Keyword != "", queryWrapper.Like("NAME", request.Keyword)).Paginator()

	count, err := s.repository.Count(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find shippingTemplates to count failed: err %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	if count == 0 {
		return paginator.Result(nil, count)
	}

	page, err := s.repository.FindPage(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find shippingTemplates to page: err: %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	return paginator.Result(page, count)
}

func (s *ShippingTemplatesService) FindById(id uint) (*dto.ShippingTemplatesDTO, error) {
	var temp *model.ShippingTemplates
	var result = &dto.ShippingTemplatesDTO{}

	temp, err := s.repository.FindById(s.db, id)
	if err != nil {
		loggerV2.Errorf("find byId shippingTemplates failed: err %v, id %d", err, id)
		return nil, err
	}

	result.ShippingTemplates = temp

	region, err := s.regionService.FindByIdRegion(temp.Id)
	if err != nil {
		return nil, err
	}
	result.RegionList = region

	if temp.Appoint == constant.GLOBAL_ENABLE {
		free, err := s.freeService.FindFree(temp.Id)
		if err != nil {
			return nil, err
		}
		result.AppointList = free
	}

	if temp.NoDelivery == constant.GLOBAL_ENABLE {
		delivery, err := s.noDeliveryService.FindNoDelivery(temp.Id)
		if err != nil {
			return nil, err
		}
		result.NoDeliveryList = delivery
	}

	return result, nil
}

func (s *ShippingTemplatesService) BatchDelete(ids []uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		if err := s.repository.BatchDelete(tx, ids); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplates failed: err %v, ids %d", err, ids)
			return err
		}

		if err := s.regionService.BatchDelete(tx, ids); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesRegion failed: err %v, ids %d", err, ids)
			return err
		}

		if err := s.freeService.BatchDelete(tx, ids); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesFree failed: err %v, ids %d", err, ids)
			return err
		}

		if err := s.noDeliveryService.BatchDelete(tx, ids); err != nil {
			loggerV2.Errorf("find id batchDelete shippingTemplatesNoDelivery failed: err %v, ids %d", err, ids)
			return err
		}

		return nil
	})
}

func (s *ShippingTemplatesService) FindSimple() ([]*model.ShippingTemplates, error) {
	rows, err := s.repository.Find(s.db)
	if err != nil {
		loggerV2.Error(err)
		return nil, err
	}

	return rows, nil
}
